package cn.cellcom.agent.online.client;

import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.Map;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.cellcom.agent.common.AgentConstant;
import cn.cellcom.agent.online.TaskEngine;
import cn.cellcom.agent.online.dispatcher.SelectorManager;
import cn.cellcom.agent.online.message.MessageConstant;
import cn.cellcom.agent.online.message.MessageConstant.ARCHIVE_EVENT;
import cn.cellcom.agent.online.wrapper.SessionWrapper;

public class Queue {
	private Logger log = LoggerFactory.getLogger(this.getClass());

	private String key;

	public Queue(String key) {
		this.key = key;
		startDetectionTask();
	}

	Map<String, SessionWrapper> sessions = new ConcurrentHashMap<String, SessionWrapper>();

	/**
	 * 加入队列并返回当前位置，-1表示被即刻接入了
	 * 
	 * @param session
	 * @return
	 */
	public int addQueue(SessionWrapper session) {
		VisitorClient visitor = session.getVisitor();
		AgentClient ac = SelectorManager.getSelector(session.getSetting().getSessionDispatchPolicy()).bestAgentFrom(session);
		// 如果找到合适的坐席，则直接进行接收会话不需要排队
		if (ac != null) {
			log.info("[{}] receive the session[{}] of visitor[{}] by immediate.", ac.getId(), session.getId(), visitor.getId());
			ac.receiveSession(session);
			return -1;
		} else {
			sessions.put(session.getId(), session);
			log.info("[{}] add session[{}] to queue and queue size is {}", session.getVisitor().getId(), session.getId(), sessions.size());

			for (AgentClient agent : session.getGroup().getAgents().values()) {
				agent.notifyQueueAdded(session);
			}
		}

		return sessions.size();
	}

	/**
	 * 取消本人排队，并改变其他访客的排队位置，以及通知坐席
	 * 
	 */
	public SessionWrapper removeQueue(SessionWrapper session) {
		SessionWrapper removed = sessions.remove(session.getId());
		if (removed != null) {// 正常来说肯定是能移除一个排队对象
			log.info("[{}] remove session[{}] from queue and queue size is {}", session.getVisitor().getId(), session.getId(), sessions.size());
			// 执行通知其他访客[注意：这里要采用被通知的访客进行发送消息]
			LinkedList<SessionWrapper> list = getIndexQueue();
			for (int i = 0; i < list.size(); i++) {
				SessionWrapper qsession = list.get(i);
				int n = QueueManager.getInstance().getQueue(qsession.getPid()).getPosition(qsession.getId()) + 1;
				long x = (System.currentTimeMillis() - qsession.getSession().getQueueTime()) / 1000;
				String text = "{\"n\":\"" + n + "\", \"x\":\"" + x + "\"}";
				qsession.getSystem().sysSendNotify(qsession.getSession().getCrm(), MessageConstant.MESSAGE_NOTIFY.QUEUE_POSITION, text);
			}
			// 通知企业内的坐席
			Map<String, AgentClient> agents = null;
			if (session != null && session.getGroup() != null) {
				agents = session.getGroup().getAgents();
			}
			if (agents != null) {
				for (AgentClient agent : agents.values()) {
					agent.notifyQueueRemoved(session);
				}
			} else {
				log.error("Why no agents in group [{}] for session[{}]", session.getGroup(), session.getId());
			}
		}
		return removed;
	}

	/**
	 * 排队无效
	 * 
	 * @param session
	 */
	public void queueOvertime(SessionWrapper session) {
		log.info("[{}] 's session[{}] in queue is abandoned, now to cancel it.", session.getVisitor().getCrm(), session.getId());
		session.getVisitor().archive(session, ARCHIVE_EVENT.QUEUE_OVER_TIME, null);
		session.getVisitor().cancelQueue(session.getId(), AgentConstant.SESSION_END_TYPE.BY_QUEUE_OVER_TIME);
	}

	/**
	 * 获取会话的排队位置
	 * 
	 * @param sid
	 * @return
	 */
	public int getPosition(String sid) {
		SessionWrapper session = sessions.get(sid);
		LinkedList<SessionWrapper> allSession = new LinkedList<SessionWrapper>();
		for (SessionWrapper r : sessions.values()) {
			allSession.add(r);
		}
		Collections.sort(allSession, new Comparator<SessionWrapper>() {
			// 先排序
			@Override
			public int compare(SessionWrapper o1, SessionWrapper o2) {
				int cmp = o1.getCrmLevel().compareTo(o2.getCrmLevel());
				if (cmp == 0 || o1.getSetting().getVisitorQueuePolicy() == AgentConstant.VISITOR_QUEUE_POLICY.BY_TIME.ordinal()) {// 等级相同则看时间，或者仅按照时间排序
					return o1.getSession().getQueueTime().compareTo(o2.getSession().getQueueTime());
				} else {
					return cmp;
				}
			}
		});
		return allSession.indexOf(session);
	}

	/**
	 * 
	 * @param crmId
	 * @return
	 */
	public SessionWrapper getSession(String crmId) {
		for (SessionWrapper r : sessions.values()) {
			if (r.getVisitor().getId().equals(crmId)) {
				return r;
			}
		}
		return null;
	}

	/**
	 * 排序后的队列
	 * 
	 * @param visitor
	 * @return
	 */
	public LinkedList<SessionWrapper> getIndexQueue() {
		LinkedList<SessionWrapper> allSession = new LinkedList<SessionWrapper>();
		for (SessionWrapper r : sessions.values()) {
			allSession.add(r);
		}
		Collections.sort(allSession, new Comparator<SessionWrapper>() {
			// 先排序
			@Override
			public int compare(SessionWrapper o1, SessionWrapper o2) {
				return o1.getSession().getQueueTime().compareTo(o2.getSession().getQueueTime());
			}
		});
		return allSession;
	}

	// ////////////////////////////////////////排队队列检测///////////////////////////////
	class QueueDetectionTask extends TimerTask {
		int count = 0;

		@Override
		public void run() {
			if (count++ > 100) {
				log.info("[{}] queue size is [{}]", key, sessions.size());
				count = 0;
			}
			for (SessionWrapper session : sessions.values()) {
				//System.out.println("--------" + session);
				if (System.currentTimeMillis() - session.getSession().getQueueTime() > session.getQueueLimitTime()) {
					queueOvertime(session);
				} else {//
					VisitorClient visitor = session.getVisitor();
					AgentClient ac = SelectorManager.getSelector(session.getSetting().getSessionDispatchPolicy()).bestAgentFrom(session);
					// 找到合适的坐席进行接收会话
					if (ac != null) {
						log.info("[{}] receive the session[{}] of visitor[{}] by dispatched.", ac.getId(), session.getId(), visitor.getId());
						ac.receiveSession(session);
					}
				}
			}
		}
	}

	QueueDetectionTask queueDetectionTask = null;

	public void startDetectionTask() {
		if (queueDetectionTask == null) {
			queueDetectionTask = new QueueDetectionTask();
			TaskEngine.getInstance().scheduleAtFixedRate(queueDetectionTask, 3000, 3000);
		}

	}
}
